const {
  loadFixture,
} = require("@nomicfoundation/hardhat-toolbox/network-helpers");
const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("SNS", function () {
  const FEE = ethers.parseUnits("1", 18);
  async function deploySNSFixture() {
    const [user1, user2, user3] = await ethers.getSigners();
    const SNS = await ethers.getContractFactory("SNS");
    const sns = await SNS.deploy(FEE);
    
    return {sns, user1, user2, user3};
  }

  async function registerFIxture(){
    const {sns,user1,user2,user3} = await loadFixture(deploySNSFixture);
    const domain1 = "domain1";
    const domain2 = "domain2";
    await sns.connect(user1).register(domain1,user1.address,{value: FEE});
    await sns.connect(user2).register(domain2,user2.address,{value: FEE});
    return {sns,user1,user2,user3,domain1,domain2};
  }

  describe("Deployment",async ()=>{
    it("Should have owner",async ()=>{
      const {sns,user1} = await loadFixture(deploySNSFixture);
      expect(await sns.owner()).to.equal(user1.address);
    })

    it("Should have fee",async ()=>{
      const {sns} = await loadFixture(deploySNSFixture);
      expect(await sns.FEE()).to.equal(FEE);
    })
  })

  describe("Register",async ()=>{
    it("Should register correctly",async ()=>{
      const {sns,user1} = await loadFixture(deploySNSFixture);
      const domain1 = "domain1";
      await sns.connect(user1).register(domain1,user1.address ,{value: FEE});
    })

    it("Should resolve correctly",async ()=>{
      const {sns,user1} = await loadFixture(deploySNSFixture);
      const domain1 = "domain1";
      await sns.connect(user1).register(domain1,user1.address,{value: FEE});
      expect(await sns.resolve(domain1)).to.equal(user1.address);
    })

    it("Should reverse correctly",async ()=>{
      const {sns,user1} = await loadFixture(deploySNSFixture);
      const domain1 = "domain1";
      await sns.connect(user1).register(domain1,user1.address,{value: FEE});
      expect(await sns.reverse(user1.address)).to.equal(domain1);
    })

    //错误情况
    it("Should not register with insufficient fee",async ()=>{
      const {sns,user1} = await loadFixture(deploySNSFixture);
      const domain1 = "domain1";
      await expect(sns.connect(user1).register(domain1,user1.address)).to.be.revertedWith("Insufficient registration fee");
    })

    it("Should not registered yet",async ()=>{
      const {sns,user1,user2} = await loadFixture(deploySNSFixture);
      const domain1 = "domain1";
      await sns.connect(user2).register(domain1,user2.address,{value: FEE});
      await expect(sns.connect(user1).register(domain1,user1.address,{value:FEE})).to.be.revertedWith("Domain already registered");
    })

    it("Should not linked to another domain",async ()=>{
      const {sns, user1} = await loadFixture(deploySNSFixture);
      const domain1 = "domain1";
      const domain2 = "domain2";
      await sns.connect(user1).register(domain1,user1.address,{value: FEE});
      await expect(sns.connect(user1).register(domain2,user1.address,{value: FEE})).to.be.revertedWith("Address already linked to a domain");
    })
  })

  describe("Sale",async ()=>{
    it("Should pending sale correctly",async ()=>{
      const {sns,user1,user2,domain1,domain2} = await loadFixture(registerFIxture);
      const price = ethers.parseUnits("1",18);
      await sns.connect(user1).listForSale(price);
      const len = await sns.getDomainsForSaleLength();
      expect(len).to.equal(1);
      const domainIndex = await sns.domainsForSale(0);
      const domain = await sns.domains(domainIndex);
      expect(domain).to.equal(domain1);
    })

    it("Should cancel sale correctly",async ()=>{
      const {sns,user1,user2,domain1,domain2} = await loadFixture(registerFIxture);
      const price = ethers.parseUnits("1",18);
      await sns.connect(user1).listForSale(price);
      await sns.connect(user1).cancelSale();
      const len = await sns.getDomainsForSaleLength();
      expect(len).to.equal(0);
    })

    it("Should buy correctly",async ()=>{
      const {sns,user1,user3,domain1} = await loadFixture(registerFIxture);
      const price = ethers.parseUnits("1",18);
      await sns.connect(user1).listForSale(price);
      await sns.connect(user3).buy(0,{value:price});

      const len = await sns.getDomainsForSaleLength();
      expect(len).to.equal(0);

      expect(await sns.resolve(domain1)).to.equal(user3.address);
      expect(sns.reverse(user1.address)).to.be.revertedWith("Address not linked to any domain");
      expect(await sns.reverse(user3.address)).to.equal(domain1);
    })
    
    //错误情况，太多了就不测了
  })

  describe("Deregister",async ()=>{
    it("Should disregister correctly",async ()=>{
      const {sns,user1,domain1} = await loadFixture(registerFIxture);
      await sns.connect(user1).deregister();
      await expect(sns.resolve(domain1)).to.be.revertedWith("Domain not registered");
      await expect(sns.reverse(user1.address)).to.be.revertedWith("Address not linked to any domain");
    })
  })
});
